/**
 * 实战1 -> 应对不稳定的网络环境 - 指数补偿
 * 0 ms
 * 200 ms
 * 400 ms
 * 800 ms
 * 1600 ms
 * 3200 ms
 * fail
 */

import fetch from "node-fetch";

function request(url) {
  let resolved = false; // 数据是否有返回
  let t = 1; // 用于指数补偿  1 2 4 8 16

  return new Promise((resolve) => {
    doFetch();
    function doFetch() {
      if (resolved || t > 16) return;
      fetch(url)
        .then((resp) => {
          return resp.text();
        })
        .then((data) => {
          if (!resolved) {
            console.log("t = ", t);
            resolve(data);
            resolved = true;
          }
        });
      setTimeout(() => {
        doFetch();
        t *= 2;
      }, t * 100);
    }
  });
}

function wait(fn, ms = 1000) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(fn());
    }, ms);
  });
}
function request1(url) {
  return Promise.race([
    fetch(url),
    wait(() => fetch(url), 100),
    wait(() => fetch(url), 200),
    wait(() => fetch(url), 400),
    wait(() => fetch(url), 800),
    wait(() => fetch(url), 1600),
  ]);
}
// request1("https://www.baidu.com").then((resp) => {
//   console.log(resp);
// });

/**
 * 实战2 -> 应对时间窗口内的重复http请求（并发处理）  ---> 时间窗口
 *
 * 多个资源并发请求 -- Promise.all
 * 基于时间窗口 过滤重复请求
 */
function hash(...args) {
  return args.join(",");
}
function window_it(f, time = 50) {
  let w = {}; // 窗口请求
  let flag = false; // 是否要重新创建新的时间窗口

  return (...args) => {
    return new Promise((resolve) => {
      if (!w[hash(args)]) {
        w[hash(args)] = {
          func: f,
          args,
          resolvers: [],
        };
      }

      if (!flag) {
        flag = true;
        setTimeout(() => {
          Object.keys(w).forEach((key) => {
            const { func, args, resolvers } = w[key];
            console.log("run once--"); // 只发送一次网络请求
            func(...args) // 调用窗口函数
              .then((resp) => {
                return resp.text();
              })
              .then((text) => {
                resolvers.forEach((r) => {
                  console.log("result anywhere --");
                  r(text); // 调用promise的resolve
                });
                flag = false;
                w = {};
              });
          });
        }, time);
      }
      w[hash(args)].resolvers.push(resolve);
    });
  };
}

// 用法
const request2 = window_it(fetch, 20);

// 加上时间窗口后，时间窗口内的同一个请求只会发一个
let a = request2("https://www.baidu.com");
request2("https://www.baidu.com");
request2("https://www.baidu.com");
request2("https://www.baidu.com");

a.then((res) => {
  console.log("res", res);
});
